home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / osrc.arc / IP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-28  |  11.6 KB  |  472 lines

  1. /* Upper half of IP, consisting of send/receive primitives, including
  2.  * fragment reassembly, for higher level protocols.
  3.  * Not needed when running as a standalone gateway.
  4.  */
  5. #define    TLB    30 * (1000/MSPTICK)    /* Reassembly limit time */
  6. #include "global.h"
  7. #include "config.h"
  8. #include "mbuf.h"
  9. #include "timer.h"
  10. #include "internet.h"
  11. #include "iface.h"
  12. #include "ip.h"
  13. #include "icmp.h"
  14.  
  15. extern struct raw_ip *Raw_ip;
  16. extern struct mbuf *Hopper;
  17. #ifdef    TRACE
  18. extern struct iface Loopback;
  19. #endif
  20.  
  21. static struct mbuf *fraghandle();
  22. static void ip_timeout(),free_reasm(),freefrag();
  23. static struct reasm *lookup_reasm(),*creat_reasm();
  24. static struct frag *newfrag();
  25.  
  26.  
  27. char Ip_ttl = MAXTTL;    /* Default time-to-live for IP datagrams */
  28. struct reasm *Reasmq;
  29. struct raw_ip *Raw_ip;
  30.  
  31. #define    INSERT    0
  32. #define    APPEND    1
  33. #define    PREPEND    2
  34.  
  35. /* Send an IP datagram. Modeled after the example interface on p 32 of
  36.  * RFC 791
  37.  */
  38. int
  39. ip_send(source,dest,protocol,tos,ttl,bp,length,id,df)
  40. int32 source;            /* source address */
  41. int32 dest;            /* Destination address */
  42. char protocol;            /* Protocol */
  43. char tos;            /* Type of service */
  44. char ttl;            /* Time-to-live */
  45. struct mbuf *bp;        /* Data portion of datagram */
  46. int16 length;            /* Optional length of data portion */
  47. int16 id;            /* Optional identification */
  48. char df;            /* Don't-fragment flag */
  49. {
  50.     struct mbuf *tbp;
  51.     struct ip ip;        /* Pointer to IP header */
  52.     static int16 id_cntr;    /* Datagram serial number */
  53.     struct phdr *phdr;
  54.  
  55.     if(length == 0 && bp != NULLBUF)
  56.         length = len_mbuf(bp);
  57.     if(id == 0)
  58.         id = id_cntr++;        
  59.     if(ttl == 0)
  60.         ttl = Ip_ttl;
  61.  
  62.     /* Fill in IP header */
  63.     ip.tos = tos;
  64.     ip.length = IPLEN + length;
  65.     ip.id = id;
  66.     ip.offset = 0;
  67.     ip.flags.mf = 0;
  68.     ip.flags.df = df;
  69.     ip.ttl = ttl;
  70.     ip.protocol = protocol;
  71.     ip.source = source;
  72.     ip.dest = dest;
  73.     ip.optlen = 0;
  74.     if((tbp = htonip(&ip,bp)) == NULLBUF){
  75.         free_p(bp);
  76.         return -1;
  77.     }
  78.     if((bp = pushdown(tbp,sizeof(struct phdr))) == NULLBUF){
  79.         free_p(tbp);
  80.         return -1;
  81.     }
  82.     phdr = (struct phdr *)bp->data;
  83. #ifdef    TRACE
  84.     if(ip.dest == Ip_addr)
  85.         phdr->iface = &Loopback;
  86.     else
  87.         phdr->iface = NULLIF;
  88. #else
  89.     phdr->iface = NULLIF;
  90. #endif
  91.     phdr->type = TYPE_IP;    
  92.     enqueue(&Hopper,bp);
  93.     return 0;
  94. }
  95.  
  96. /* Reassemble incoming IP fragments and dispatch completed datagrams
  97.  * to the proper transport module
  98.  */
  99. void
  100. ip_recv(ip,bp,rxbroadcast)
  101. struct ip *ip;        /* Extracted IP header */
  102. struct mbuf *bp;    /* Data portion */
  103. char rxbroadcast;    /* True if received on subnet broadcast address */
  104. {
  105.     void (*recv)();    /* Function to call with completed datagram */
  106.     register struct raw_ip *rp;
  107.     struct mbuf *bp1,*tbp;
  108.     int rxcnt = 0;
  109.  
  110.     /* If we have a complete packet, call the next layer
  111.      * to handle the result. Note that fraghandle passes back
  112.      * a length field that does NOT include the IP header
  113.      */
  114.     if((bp = fraghandle(ip,bp)) == NULLBUF)
  115.         return;        /* Not done yet */
  116.  
  117.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next){
  118.         if(rp->protocol != ip->protocol)
  119.             continue;
  120.         rxcnt++;
  121.         /* Duplicate the data portion, and put the header back on */
  122.         dup_p(&bp1,bp,0,len_mbuf(bp));
  123.         if(bp1 != NULLBUF && (tbp = htonip(ip,bp1)) != NULLBUF){
  124.             enqueue(&rp->rcvq,tbp);
  125.             if(rp->r_upcall != NULLVFP)
  126.                 (*rp->r_upcall)(rp);
  127.         } else {
  128.             free_p(bp1);
  129.         }
  130.     }
  131.     /* Check for protocols we can't handle */
  132.     switch(uchar(ip->protocol)){
  133.     case TCP_PTCL:
  134.         recv = tcp_input;
  135.         break;
  136.     case UDP_PTCL:
  137.         recv = udp_input;
  138.         break;
  139.     case ICMP_PTCL:
  140.         recv = icmp_input;
  141.         break;
  142.     default:
  143.         recv = NULLVFP;
  144.         break;
  145.     }
  146.     if(recv != NULLVFP){
  147.         /* Pass the completed packet upstairs */
  148.         (*recv)(bp,ip->protocol,ip->source,ip->dest,ip->tos,
  149.             ip->length - (IPLEN + ip->optlen),rxbroadcast);
  150.     } else {
  151.         if(rxcnt == 0){
  152.             /* Send an ICMP Protocol Unknown response... */
  153.             Ip_stats.badproto++;
  154.             /* ...unless it's a broadcast */
  155.             if(!rxbroadcast){
  156.                 icmp_output(ip,bp,DEST_UNREACH,PROT_UNREACH,(union icmp_args *)NULL);
  157.             }
  158.         }
  159.         free_p(bp);
  160.     }
  161. }
  162. /* Process IP datagram fragments
  163.  * If datagram is complete, return it with ip->length containing the data
  164.  * length (MINUS header); otherwise return NULLBUF
  165.  */
  166. static
  167. struct mbuf *
  168. fraghandle(ip,bp)
  169. struct ip *ip;        /* IP header, host byte order */
  170. struct mbuf *bp;    /* The fragment itself */
  171. {
  172.     register struct reasm *rp; /* Pointer to reassembly descriptor */
  173.     struct frag *lastfrag,*nextfrag,*tfp;
  174.     struct mbuf *tbp;
  175.     int16 i;
  176.     int16 last;        /* Index of first byte beyond fragment */
  177.  
  178.     last = ip->offset + ip->length - (IPLEN + ip->optlen);
  179.  
  180.     rp = lookup_reasm(ip);
  181.     if(ip->offset == 0 && !ip->flags.mf){
  182.         /* Complete datagram received. Discard any earlier fragments */
  183.         if(rp != NULLREASM)
  184.             free_reasm(rp);
  185.  
  186.         return bp;
  187.     }
  188.     if(rp == NULLREASM){
  189.         /* First fragment; create new reassembly descriptor */
  190.         if((rp = creat_reasm(ip)) == NULLREASM){
  191.             /* No space for descriptor, drop fragment */
  192.             free_p(bp);
  193.             return NULLBUF;
  194.         }
  195.     }
  196.     /* Keep restarting timer as long as we keep getting fragments */
  197.     stop_timer(&rp->timer);
  198.     start_timer(&rp->timer);
  199.  
  200.     /* If this is the last fragment, we now know how long the
  201.      * entire datagram is; record it
  202.      */
  203.     if(!ip->flags.mf)
  204.         rp->length = last;
  205.  
  206.     /* Set nextfrag to the first fragment which begins after us,
  207.      * and lastfrag to the last fragment which begins before us
  208.      */
  209.     lastfrag = NULLFRAG;
  210.     for(nextfrag = rp->fraglist;nextfrag != NULLFRAG;nextfrag = nextfrag->next){
  211.         if(nextfrag->offset > ip->offset)
  212.             break;
  213.         lastfrag = nextfrag;
  214.     }
  215.     /* Check for overlap with preceeding fragment */
  216.     if(lastfrag != NULLFRAG  && ip->offset < lastfrag->last){
  217.         /* Strip overlap from new fragment */
  218.         i = lastfrag->last - ip->offset;
  219.         pullup(&bp,NULLCHAR,i);
  220.         if(bp == NULLBUF)
  221.             return NULLBUF;    /* Nothing left */
  222.         ip->offset += i;
  223.     }
  224.     /* Look for overlap with succeeding segments */
  225.     for(; nextfrag != NULLFRAG; nextfrag = tfp){
  226.         tfp = nextfrag->next;    /* save in case we delete fp */
  227.  
  228.         if(nextfrag->offset >= last)
  229.             break;    /* Past our end */
  230.         /* Trim the front of this entry; if nothing is
  231.          * left, remove it.
  232.          */
  233.         i = last - nextfrag->offset;
  234.         pullup(&nextfrag->buf,NULLCHAR,i);
  235.         if(nextfrag->buf == NULLBUF){
  236.             /* superseded; delete from list */
  237.             if(nextfrag->prev != NULLFRAG)
  238.                 nextfrag->prev->next = nextfrag->next;
  239.             else
  240.                 rp->fraglist = nextfrag->next;
  241.             if(tfp->next != NULLFRAG)
  242.                 nextfrag->next->prev = nextfrag->prev;
  243.             freefrag(nextfrag);
  244.         } else
  245.             nextfrag->offset = last;
  246.     }
  247.     /* Lastfrag now points, as before, to the fragment before us;
  248.      * nextfrag points at the next fragment. Check to see if we can
  249.      * join to either or both fragments.
  250.      */
  251.     i = INSERT;
  252.     if(lastfrag != NULLFRAG && lastfrag->last == ip->offset)
  253.         i |= APPEND;
  254.     if(nextfrag != NULLFRAG && nextfrag->offset == last)
  255.         i |= PREPEND;
  256.     switch(i){
  257.     case INSERT:    /* Insert new desc between lastfrag and nextfrag */
  258.         tfp = newfrag(ip->offset,last,bp);
  259.         tfp->prev = lastfrag;
  260.         tfp->next = nextfrag;
  261.         if(lastfrag != NULLFRAG)
  262.             lastfrag->next = tfp;    /* Middle of list */
  263.         else
  264.             rp->fraglist = tfp;    /* First on list */
  265.         if(nextfrag != NULLFRAG)
  266.             nextfrag->prev = tfp;
  267.         break;
  268.     case APPEND:    /* Append to lastfrag */
  269.         append(&lastfrag->buf,bp);
  270.         lastfrag->last = last;    /* Extend forward */
  271.         break;
  272.     case PREPEND:    /* Prepend to nextfrag */
  273.         tbp = nextfrag->buf;
  274.         nextfrag->buf = bp;
  275.         append(&nextfrag->buf,tbp);
  276.         nextfrag->offset = ip->offset;    /* Extend backward */
  277.         break;
  278.     case (APPEND|PREPEND):
  279.         /* Consolidate by appending this fragment and nextfrag
  280.          * to lastfrag and removing the nextfrag descriptor
  281.          */
  282.         append(&lastfrag->buf,bp);
  283.         append(&lastfrag->buf,nextfrag->buf);
  284.         nextfrag->buf = NULLBUF;
  285.         lastfrag->last = nextfrag->last;
  286.  
  287.         /* Finally unlink and delete the now unneeded nextfrag */
  288.         lastfrag->next = nextfrag->next;
  289.         if(nextfrag->next != NULLFRAG)
  290.             nextfrag->next->prev = lastfrag;
  291.         freefrag(nextfrag);
  292.         break;
  293.     }
  294.     if(rp->fraglist->offset == 0 && rp->fraglist->next == NULLFRAG 
  295.         && rp->length != 0){
  296.         /* We've gotten a complete datagram, so extract it from the
  297.          * reassembly buffer and pass it on.
  298.          */
  299.         bp = rp->fraglist->buf;
  300.         rp->fraglist->buf = NULLBUF;
  301.         /* Tell IP the entire length */
  302.         ip->length = rp->length + (IPLEN + ip->optlen);
  303.         free_reasm(rp);
  304.         return bp;
  305.     } else
  306.         return NULLBUF;
  307. }
  308. /* Arrange for receipt of raw IP datagrams */
  309. struct raw_ip *
  310. raw_ip(protocol,r_upcall)
  311. char protocol;
  312. void (*r_upcall)();
  313. {
  314.     register struct raw_ip *rp;
  315.  
  316.     rp = (struct raw_ip *)calloc(1,sizeof(struct raw_ip));
  317.     rp->protocol = protocol;
  318.     rp->r_upcall = r_upcall;
  319.     rp->next = Raw_ip;
  320.     if(rp->next != NULLRIP)
  321.         rp->next->prev = rp;
  322.     Raw_ip = rp;
  323.     return rp;
  324. }
  325. /* Free a raw IP descriptor */
  326. void
  327. del_ip(rpp)
  328. struct raw_ip *rpp;
  329. {
  330.     register struct raw_ip *rp;
  331.  
  332.     /* Do sanity check on arg */
  333.     for(rp = Raw_ip;rp != NULLRIP;rp = rp->next)
  334.         if(rp == rpp)
  335.             break;
  336.     if(rp == NULLRIP)
  337.         return;    /* Doesn't exist */
  338.  
  339.     /* Unlink */
  340.     if(rp->prev != NULLRIP)
  341.         rp->prev->next = rp->next;
  342.     else
  343.         Raw_ip = rp->next;
  344.     if(rp->next != NULLRIP)
  345.         rp->next->prev = rp->prev;
  346.     /* Free resources */
  347.     free_q(&rp->rcvq);
  348.     free((char *)rp);
  349. }
  350.  
  351. static struct reasm *
  352. lookup_reasm(ip)
  353. struct ip *ip;
  354. {
  355.     register struct reasm *rp;
  356.  
  357.     for(rp = Reasmq;rp != NULLREASM;rp = rp->next){
  358.         if(ip->source == rp->source && ip->dest == rp->dest
  359.          && ip->protocol == rp->protocol && ip->id == rp->id)
  360.             return rp;
  361.     }
  362.     return NULLREASM;
  363. }
  364. #ifdef    FOO
  365. static
  366. int16
  367. hash_reasm(source,dest,protocol,id)
  368. int32 source;
  369. int32 dest,
  370. char protocol;
  371. int16 id;
  372. {
  373.     register unsigned int hval;
  374.  
  375.     hval = loword(source);
  376.     hval ^= hiword(source);
  377.     hval ^= loword(dest);
  378.     hval ^= hiword(dest);
  379.     hval ^= uchar(protocol);
  380.     hval ^= id;
  381.     return hval % RHASH;
  382. }
  383. #endif
  384. /* Create a reassembly descriptor,
  385.  * put at head of reassembly list
  386.  */
  387. static struct reasm *
  388. creat_reasm(ip)
  389. register struct ip *ip;
  390. {
  391.     register struct reasm *rp;
  392.  
  393.     if((rp = (struct reasm *)calloc(1,sizeof(struct reasm))) == NULLREASM)
  394.         return rp;    /* No space for descriptor */
  395.     rp->source = ip->source;
  396.     rp->dest = ip->dest;
  397.     rp->id = ip->id;
  398.     rp->protocol = ip->protocol;
  399.     rp->timer.start = TLB;
  400.     rp->timer.func = ip_timeout;
  401.     rp->timer.arg = (char *)rp;
  402.  
  403.     rp->next = Reasmq;
  404.     if(rp->next != NULLREASM)
  405.         rp->next->prev = rp;
  406.     Reasmq = rp;
  407.     return rp;
  408. }
  409.  
  410. /* Free all resources associated with a reassembly descriptor */
  411. static void
  412. free_reasm(rp)
  413. register struct reasm *rp;
  414. {
  415.     register struct frag *fp;
  416.  
  417.     stop_timer(&rp->timer);
  418.     /* Remove from list of reassembly descriptors */
  419.     if(rp->prev != NULLREASM)
  420.         rp->prev->next = rp->next;
  421.     else
  422.         Reasmq = rp->next;
  423.     if(rp->next != NULLREASM)
  424.         rp->next->prev = rp->prev;
  425.     /* Free any fragments on list, starting at beginning */
  426.     while((fp = rp->fraglist) != NULLFRAG){
  427.         rp->fraglist = fp->next;
  428.         free_p(fp->buf);
  429.         free((char *)fp);
  430.     }
  431.     free((char *)rp);
  432. }
  433.  
  434. /* Handle reassembly timeouts by deleting all reassembly resources */
  435. static void
  436. ip_timeout(arg)
  437. int *arg;
  438. {
  439.     register struct reasm *rp;
  440.  
  441.     rp = (struct reasm *)arg;
  442.     free_reasm(rp);
  443. }
  444. /* Create a fragment */
  445. static
  446. struct frag *
  447. newfrag(offset,last,bp)
  448. int16 offset,last;
  449. struct mbuf *bp;
  450. {
  451.     struct frag *fp;
  452.  
  453.     if((fp = (struct frag *)calloc(1,sizeof(struct frag))) == NULLFRAG){
  454.         /* Drop fragment */
  455.         free_p(bp);
  456.         return NULLFRAG;
  457.     }
  458.     fp->buf = bp;
  459.     fp->offset = offset;
  460.     fp->last = last;
  461.     return fp;
  462. }
  463. /* Delete a fragment, return next one on queue */
  464. static
  465. void
  466. freefrag(fp)
  467. struct frag *fp;
  468. {
  469.     free_p(fp->buf);
  470.     free((char *)fp);
  471. }
  472.